package com.spm.librarianmanagersystem.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.spm.librarianmanagersystem.mapper.*;
import com.spm.librarianmanagersystem.pojo.Book;
import com.spm.librarianmanagersystem.pojo.Borrow;
import com.spm.librarianmanagersystem.pojo.Fine;
import com.spm.librarianmanagersystem.pojo.Reservation;
import com.spm.librarianmanagersystem.service.ReservationService;
import com.spm.librarianmanagersystem.vo.ReservationAdminDetail;
import org.apache.ibatis.transaction.TransactionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.security.InvalidParameterException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

@Service("ReservationService")
public class ReservationServiceImpl implements ReservationService {
    private static final String url = "https://rabbitmq-test-web-framework-bkbidotkwo.cn-hangzhou.fcapp.run/send";
    private static final int MAX_BORROW = 5;

    @Autowired
    ReservationMapper mapper;
    @Autowired
    MemberMapper memberMapper;
    @Autowired
    BookMapper bookMapper;
    @Autowired
    BorrowMapper borrowMapper;
    @Autowired
    FineMapper fineMapper;
    @Autowired
    private SendEmailImpl sei;
    @Autowired
    private MessageMapper mm;

    @Autowired
    private RestTemplate restTemplate;

    @Override
    public JSONArray getReservations(String currentUserId) {
        List<Reservation> reservations = mapper.getReservations(currentUserId);
        return (JSONArray) JSONArray.toJSON(reservations);
    }

    @Override
    public JSONObject getOneReservation(String currentUserId, Integer reservationId) {
        Reservation reservation = mapper.getOneReservation(currentUserId, reservationId);
        return (JSONObject) JSONObject.toJSON(reservation);
    }

    @Override
    @Transactional
    public String reserve(String currentUserId, String isbn) {
        // 判断是否重复预约
        List<Reservation> reservations = mapper.getReservations(currentUserId);
        for (Reservation reservation : reservations) {
            if (reservation.getISBN().equals(isbn) && reservation.getStatus().equals(1)) {
                throw new TransactionException("正在预约本书, 不能重复预约");
            }
        }

        // 判断是否有库存
        Integer available = bookMapper.countBook(isbn) - borrowMapper.getBorrowCount(isbn);
        if (available != 0) {
            throw new TransactionException("图书有库存，可直接借阅");
        }

        List<Borrow> borrows = borrowMapper.getBorrowingList(currentUserId);
        Date now = new Date(System.currentTimeMillis());
        for (Borrow borrow : borrows) {
            // 判断预约的书是否已被本人借出
            if (borrow.getISBN().equals(isbn)) {
                throw new TransactionException("正在借阅本书, 预约失败");
            }
            // 判断是否有超期未还的图书
            if (now.after(borrow.getDueTime())) {
                throw new TransactionException("有逾期未还的图书, 预约失败");
            }
        }
        // 判断是否超过借阅上限
        if (MAX_BORROW == borrows.size()) {
            throw new TransactionException("借阅图书已达上限, 无法预约");
        }
        // 判断是否有未缴纳的罚款
        List<Fine> fines = fineMapper.getFineList(currentUserId);
        for (Fine fine : fines) {
            if (fine.getAmount() > 0) {
                throw new TransactionException("有未缴纳的罚款, 预约失败");
            }
        }
        Integer userId = memberMapper.getMemberByID(currentUserId).getUserId();
//        Boolean ok = mapper.addReservation(userId, isbn, new Date(System.currentTimeMillis()));
        // 及时获取reservationId 换种add方式
        Reservation reservation = new Reservation();
        reservation.setISBN(isbn);
        reservation.setReservationTime(new Date());
        reservation.setStatus(1);
        reservation.setUserId(userId);
        Boolean ok = mapper.addReser(reservation);
        if (ok == null || !ok) {
            throw new TransactionException("预约失败");
        }
        this.sendMessage(reservation.getReservationId(), currentUserId);
        return "操作成功!";
    }

    @Override
    public String cancel(String currentUserId, Integer reservationId) {
        // 检查userId和reservationId是否对应
        Reservation reservation = mapper.getOneReservation(currentUserId, reservationId);
        if (reservation == null) {
            throw new InvalidParameterException("未找到预约记录");
        }
        if (reservation.getStatus() == 0) {
            throw new TransactionException("预约已经被取消");
        }
        if (reservation.getStatus() == 2) {
            throw new TransactionException("预约已完成, 不能被取消");
        }

        Boolean ok = mapper.updateReservationForCancel(reservationId);
        if (ok == null || !ok) {
            throw new TransactionException("取消预约失败");
        }
        return "操作成功!";
    }

    @Override
    public JSONArray getReservationsAdminDetail() {
        List<ReservationAdminDetail> result = new ArrayList<>();
        List<Book> books = bookMapper.getAllBook();
        for (Book book : books) {
            ReservationAdminDetail detail = new ReservationAdminDetail();
            detail.setBookInfo(book);
            List<String> members = mapper.getReservingMembers(book.getISBN());
            if (members == null) {
                members = new ArrayList<>();
            }
            detail.setMembers(members);
            detail.setNumber(members.size());
            detail.setStatus(members.size() > 0 ? 1 : 0);
            result.add(detail);
        }
        return (JSONArray) JSONArray.toJSON(result);
    }

    @Override
    public Boolean cancelReser(Integer reservationId, String currUserId) throws Exception {
        System.out.println("reservationId: " + reservationId + "currUserId: " + currUserId);
        Reservation reservation = mapper.getRerservationByReserID(reservationId);
        System.out.println(LocalDateTime.now()  + "_reservation: " + reservation);
        if (reservation != null && reservation.getStatus() != 0 && reservation.getStatus() != 2) {
            Boolean ok = mapper.updateReservationForCancel(reservationId);
            if (ok == null || !ok) {
                throw new TransactionException("取消预约失败");
            }
            String email = memberMapper.getEmailByID(currUserId);
            sei.sendAuthCodeEmail(email, reservation);
            this.cancel(currUserId,reservationId);
            // 超期消息加入message表
            Integer userIDByID = memberMapper.getUserIDByID(currUserId);
            String bookName = bookMapper.getABook(mapper.getRerservationByReserID(reservationId).getISBN()).getBookName();
            mm.addReserOverDueMes("Reservation Overdue", "Your Reservation for "+bookName+" has expired and cancelled",
                    new Date(), reservationId, userIDByID);
            return true;
        }
        return false;
    }

    // KAI
    // 过程1 后端调用消息队列
    private void sendMessage(Integer reservationId, String currUserId) {
        JSONObject obj = new JSONObject();
        obj.put("expiration", 10000);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("currReserId", reservationId);
        jsonObject.put("currUserId", currUserId);
        obj.put("msg", jsonObject.toJSONString());
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
        httpHeaders.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
        HttpEntity<String> request = new HttpEntity<>(obj.toJSONString(), httpHeaders);
        String o = restTemplate.postForObject(url, request, String.class);
        System.out.println(LocalDateTime.now()  + "_过程1请求的响应： " + o);
    }
}
